#include "bignumber.cpp"
#include "fstream"
#include "RSA.cpp"
#define DEBUG 2
#define PROC "RSA"

using namespace std;
BigInteger ck = numThree; 
BigInteger num16 = string("16");

BigInteger hex2string(string str)
{
    BigInteger a,t=1;
    int c = 1;
    for (int i=str.length()-1;i>=0;i--)
    {
        if (str.c_str()[i]=='0')
            c=0x00;
        else if (str.c_str()[i]=='1')
            c=0x01;
        else if (str.c_str()[i]=='2')
            c=0x02;
        else if (str.c_str()[i]=='3')
            c=0x03;
        else if (str.c_str()[i]=='4')
            c=0x04;
        else if (str.c_str()[i]=='5')
            c=0x05;
        else if (str.c_str()[i]=='6')
            c=0x06;
        else if (str.c_str()[i]=='7')
            c=0x07;
        else if (str.c_str()[i]=='8')
            c=0x08;
        else if (str.c_str()[i]=='9')
            c=0x09;
        else if (str.c_str()[i]=='A')
            c=0x0a;
        else if (str.c_str()[i]=='B')
            c=0x0b;
        else if (str.c_str()[i]=='C')
            c=0x0c;
        else if (str.c_str()[i]=='D')
            c=0x0d;
        else if (str.c_str()[i]=='E')
            c=0x0e;
        else if (str.c_str()[i]=='F')
            c=0x0f;
        a += t*c;
        t=t*num16;
    }
    return a;
}
string string2hex(string str)
{
    BigInteger s = str;
    stack<char> t;
    char res = '0';
    string tmp;
 
    while (!s.equals(numZero))
    {
        BigInteger h = s%num16;
        s = s/num16;
        if (h==0){
		    res='0';	}
        else if(h==1){
            res='1';	}
        else if(h==2){
            res='2';	}
        else if(h==3){
            res='3';	}
        else if(h==4){
            res='4';	}
        else if(h==5){
            res='5';	}
        else if(h==6){
            res='6';	}
        else if(h==7){
            res='7';	}
        else if(h==8){
            res='8';	}
        else if(h==9){
            res='9';	}
        else if(h==10){
            res='A';	}
        else if(h==11){
            res='B';	}
        else if(h==12){
            res='C';	}
        else if(h==13){
            res='D';	}
        else if(h==14){
            res='E';	}
        else if(h==15){
            res='F';	}
        t.push(res);
    }
    stringstream ss;
    while(!t.empty())
    {
        ss<<t.top();
        t.pop();
    }
    ss>>tmp;
    return tmp;
}
void test(){

    
    
    BigInteger a = BigInteger((string)"37");
    BigInteger b = BigInteger((string)"57");
    BigInteger k = (a-numOne)*(b-numOne);
    BigInteger n = a*b;
    cout<<"n="<<string2hex(n.getNumber())<<endl;
    BigInteger res = ck.modPow(k,n);
    cout<<ck.getNumber()<<"^"<<k.getNumber()<<"="<<res.getNumber()<<" mod "<<n.getNumber();
}
void ex2()
{
    RSA rsa;
    Prime prime;
    BigInteger p = prime.generateSingle(15);
    BigInteger q = prime.generateSingle(15);
    BigInteger n = p*q;
    BigInteger phiN = (p-numOne)*(q-numOne);
    RSAFinalKey k = rsa.generateRandomKey(phiN, 2);
    BigInteger tmp = k.e*k.d;
    ck = ck.modPow(phiN,n);
    cout<<"p= "<<p.getNumber()<<" ,q= "<<q.getNumber()<<" ,n= "<<n.getNumber()<<endl;
    cout<<"p= "<<string2hex(p.getNumber())<<" ,q= "<<string2hex(q.getNumber())<<" ,n= "<<string2hex(n.getNumber())<<endl;
    cout<<"3^phiN mod N= "<<ck.getNumber()<<endl;
    cout<<"3^phiN mod N= "<<string2hex(ck.getNumber())<<endl;
    cout<<"e= "<<k.e.getNumber()<<" ,d= "<<k.d.getNumber()<<" ,phiN= "<<phiN.getNumber()<<endl;
    cout<<"e= "<<string2hex(k.e.getNumber())<<" ,d= "<<string2hex(k.d.getNumber())<<" ,phiN= "<<string2hex(phiN.getNumber())<<endl;
    ck = tmp - numOne;
    cout<<"e*d-1 = "<<ck.getNumber()<<endl;
    cout<<"e*d-1 = "<<string2hex(ck.getNumber())<<endl;
    ck = ck%phiN;
    cout<<"(e*d-1)%phiN = "<<ck.getNumber()<<endl;
    cout<<"(e*d-1)%phiN = "<<string2hex(ck.getNumber())<<endl;
}
char* plainfile,*nfile,*efile,*dfile,*cipherfile;
void print_usage() {
	printf("\n非法输入,支持的参数有以下：\n-p plainfile  指定明文文件的位置和名称\n-n nfile  指定存放整数 n 的文件的位置和名称\n-e efile  在数据加密时，指定存放整数 e 的文件的位置和名称\n-d dfile  在数字签名时，指定存放整数 d 的文件的位置和名称\n-c cipherfile  指定密文文件的位置和名称\n");
	exit(-1);
}

void parameter_process(int argc, char** argv)
{
	for (int i = 1; i < argc; i += 2) {
		if (strlen(argv[i]) != 2) {
			print_usage();
		}
		switch (argv[i][1]) {
		case 'p':
			plainfile = argv[i + 1];
			break;
		case 'n':
			nfile = argv[i + 1];
			break;
		case 'e':
			efile = argv[i + 1];
			break;
		case 'd':
			dfile = argv[i + 1];
			break;
		case 'c':
			cipherfile = argv[i + 1];
			break;
		default:
			print_usage();
		}
	}

	if (plainfile == NULL || nfile == NULL || cipherfile == NULL) {
		print_usage();
	}

}
BigInteger Encrypt(BigInteger m,BigInteger n,BigInteger e)
{
    BigInteger c = m.modPow(e,n);
    return c;
}
BigInteger Sign(BigInteger m,BigInteger n,BigInteger d)
{
    BigInteger c = m.modPow(d,n);
    return c;   
}
void ex3(int argc, char **args)
{
    parameter_process(argc, args);
    ifstream pfin,nfin,efin,dfin;
    pfin.open(plainfile, ios::in );
    nfin.open(nfile, ios::in );
    efin.open(efile, ios::in );
    dfin.open(dfile, ios::in );
    ofstream cfout;
    cfout.open(cipherfile,ios::out);
    string p,n,e,d;
    pfin>>p;
    nfin>>n;
    efin>>e;
    dfin>>d;
    BigInteger P =hex2string(p),N=hex2string(n),E=hex2string(e),D=hex2string(d);
    cfout<<"After encryption："<<string2hex(Encrypt(P,N,E).getNumber())<<endl;
    cfout<<"After signing："<<string2hex(Sign(P,N,D).getNumber())<<endl;
}
int main(int argc, char **args)
{

	srand(time(NULL));
    if (DEBUG == 1)
    {
        freopen(PROC".out","w",stdout);
        ex2();
    }
    else if (DEBUG == 2) ex3(argc,args);
}

